﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net.WebSockets;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.WebPages;
using System.Web.WebSockets;
using AspNet.Identity.MongoDB;
using Microsoft.Ajax.Utilities;
using MongoDB.Bson;
using MongoDB.Driver;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using SignatureWebApi.Models;
using NPOI.XSSF.Streaming;

namespace SignatureWebApi
{
    /// <summary>
    /// 其他功能的帮助类,
    /// </summary>
    public static class OtherHelper
    {
        public delegate Task SendProgress(string token,double message);
        private static bool IsCustomType(Type type)
        {
            return (type != typeof(object) && Type.GetTypeCode(type) == TypeCode.Object);
        }   
        /// <summary>
        /// 判断是否已经将数据填写完成
        /// </summary>
        /// <param name="data">判断的数据</param>
        /// <param name="targeType">数据嵌套的目标类型</param>
        /// <typeparam name="T">数据的类型</typeparam>
        /// <returns></returns>
        public static bool IsFilled<T>(T data,Type targeType)
        {
            var result = true;

            if (data.GetType()== targeType)
            {
                foreach (var item in data.GetType().GetProperties())
                {
                    result &=item.GetValue(data) != null;
                }
            }
            else
            {
                foreach (var item in data.GetType().GetProperties())
                {
                    if (item.GetValue(data)!=null)
                    {
                        result &= IsFilled(item.GetValue(data), targeType);
                    }
                }

                return result;
            }
            return result;
        }
        /// <summary>
        /// 计算时间差
        /// </summary>
        /// <param name="beginTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <returns>返回分钟</returns>
        public static int CountUsingTime(DateTime beginTime, DateTime endTime)
        {
            
            TimeSpan ts1 = new TimeSpan(beginTime.Ticks);
            TimeSpan ts2 = new TimeSpan(endTime.Ticks);
            var ts3 = ts2.Subtract(ts1).TotalMinutes;
            //var qqqqqqq = ts2.Subtract(ts1).TotalMinutes;
            return (int)ts3;
        }

        /// <summary>
        /// 将BsonDocument序转化为Excel的方法
        /// </summary>
        /// <param name="data"></param>
        /// <param name="sendProgerss">发送进度的方法</param>
        /// <param name="sheetName"></param>
        /// <param name="title"></param>
        /// <returns></returns>
        public static XSSFWorkbook DataConvertToExcel<T>(IEnumerable<T> data, SendProgress sendProgerss, string sheetName = "工作表1", List<string> title = null,string userToken=null)
        {
            //JArray DataObj;1
            var enumerable = data as T[] ?? data.ToArray();
            //var dataObj = (JArray)JsonConvert.DeserializeObject(enumerable.ToJson());
            var dataObj = enumerable.ToList();
            var dataLength = dataObj.Count;
            List<string> titleKey = new List<string>();
            XSSFWorkbook nopiObj = new XSSFWorkbook();//创建Excel对象
            IFont Font = nopiObj.CreateFont();//设置字体Style
            Font.FontName = "微软雅黑";
            ICellStyle cellStyle = nopiObj.CreateCellStyle();
            cellStyle.SetFont(Font);

            ISheet sheet = nopiObj.CreateSheet(sheetName);//创建Excel工作表
            IRow row = sheet.CreateRow(0);//创建行
            int c = 0;
            //编辑首行(标题)
            if (title == null)
            {

                foreach (var DataObject in dataObj[0].ToBsonDocument().ToList())
                {

                    string titleTemp = DataObject.Name.ToString();
                    //string titleTemp = DataObject.Path.Split('.')[1];
                    row.CreateCell(c).SetCellValue(titleTemp);
                    row.GetCell(c).CellStyle = cellStyle;
                    titleKey.Add(titleTemp);
                    c++;
                }
            }
            else
            {
                try
                {
                    if (dataObj.Count>0)
                    {
                        //foreach (var dataObject in dataObj[0].ToBsonDocument().ToList())
                        //{

                        //    string titleTemp = dataObject.Name.ToString();
                        //    titleKey.Add(titleTemp);
                        //}


                        //foreach (var dataObject in dataObj[0])
                        //{
                        //    string titleTemp = dataObject.Path.Split('.')[1];
                        //    titleKey.Add(titleTemp);
                        //}

                        //var type = dataObj[0].GetType().GetProperties();
                        var type=typeof(T).GetProperties();
                        foreach (var variable in type)
                        {
                            titleKey.Add(variable.Name);
                        }

                    }
                    
                    foreach (var dataObject in title)
                    {

                        string titleTemp = dataObject;
                        row.CreateCell(c).SetCellValue(titleTemp);
                        row.GetCell(c).CellStyle = cellStyle;
                        c++;
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
                
            }
            //编辑剩余行
            int i = 1;
            double progress = 0;
            foreach (var dataObject in dataObj)
            {
                var progressTemp = Math.Round((double)i / dataLength, 2);
                if (!(progressTemp == progress))
                {
                    progress = progressTemp;
                    Task.Run(() => { sendProgerss(userToken, progressTemp); });
                }
                //sendProgerss.BeginInvoke(userToken, (double) i / dataLength, null, null);
                //WebSocketHelper.SendExportProgress(userToken, (double)i / dataLength);
                //sendProgerss(userToken, (double)i / dataLength);
                IRow rowtemp = sheet.CreateRow(i);
                for (int keyCount = 0; keyCount < titleKey.Count; keyCount++)
                {
                    string CellVal = "";
                    var type = dataObject.GetType().GetProperty(titleKey[keyCount]);
                    var valTemp = type?.GetValue(dataObject);
                    CellVal = valTemp?.ToString();
                    rowtemp.CreateCell(keyCount).SetCellValue(CellVal);
                    rowtemp.GetCell(keyCount).CellStyle = cellStyle;
                }   
                //自动适应行宽
                sheet.AutoSizeColumn(i-1);
                i++;
            }
            GC.Collect();
            return nopiObj;
        }
        /// <summary>
        /// 将Json字符串(必须符合一定格式(无内嵌项))转变成Excel
        /// </summary>
        /// <param name="data"></param>
        /// <param name="SheetName"></param>
        /// <param name="title"></param>
        /// <returns></returns>
        public static XSSFWorkbook DataConvertToExcel(string data, string SheetName = "工作表1", List<string> title = null)
        {
            JArray DataObj;
            DataObj = (JArray)JsonConvert.DeserializeObject(data);//将获得的JSON字符串转换为操作对象
            List<string> TitleKey = new List<string>();//定义一个TitleKey List来保存数据键值对中的键
            XSSFWorkbook NopiObj = new XSSFWorkbook();//创建Excel对象

            IFont Font = NopiObj.CreateFont();//设置字体Style
            Font.FontName = "微软雅黑";
            ICellStyle CellStyle = NopiObj.CreateCellStyle();
            CellStyle.SetFont(Font);

            ISheet sheet = NopiObj.CreateSheet(SheetName);//创建Excel工作表
            IRow row = sheet.CreateRow(0);//创建行
            int c = 0;
            string titleTemp = "";
            //编辑首行(标题) 默认不输入标题就以数据组中的键值对的键作为标题 否则以输入的数组中的字符串作为标题
            if (title == null)
            {

                foreach (var DataObject in DataObj[0])
                {

                    titleTemp = DataObject.Path.Split('.')[1];
                    row.CreateCell(c).SetCellValue(titleTemp);
                    row.GetCell(c).CellStyle = CellStyle;
                    TitleKey.Add(titleTemp);      //将数据的key存入list
                    c++;
                }
            }
            else
            {
                foreach (var DataObject in DataObj[0])
                {

                    titleTemp = DataObject.Path.Split('.')[1];
                    TitleKey.Add(titleTemp);    //将数据的key存入list
                }
                foreach (var DataObject in title)
                {

                    titleTemp = DataObject.ToString();
                    row.CreateCell(c).SetCellValue(titleTemp);
                    row.GetCell(c).CellStyle = CellStyle;
                    c++;
                }
            }

            //编辑剩余行
            int i = 1;
            foreach (var DataObject in DataObj)
            {
                IRow rowtemp = sheet.CreateRow(i);
                //c = 0;
                //foreach (var Data in DataObj[i - 1])
                //{
                //    string CellData = Data.First.ToString();
                //    rowtemp.CreateCell(c).SetCellValue(CellData);
                //    rowtemp.GetCell(c).CellStyle = CellStyle;

                //    c++;
                //}
                for (int KeyCount = 0; KeyCount < TitleKey.Count; KeyCount++)
                {
                    rowtemp.CreateCell(KeyCount).SetCellValue(DataObj[i - 1][TitleKey[KeyCount]].ToString());
                    rowtemp.GetCell(KeyCount).CellStyle = CellStyle;
                }
                i++;
            }
            //自动适应行宽
            for (int rowcount = 0; rowcount <= i - 1; rowcount++)
            {
                sheet.AutoSizeColumn(rowcount);
            }
            return NopiObj;
        }

        public static StandAreaEnum? StandToAreaEnum(string stand)
        {

            var standArea = new StandArea();
            Type modelType = standArea.GetType();
            PropertyInfo[] propertyList = modelType.GetProperties();
            foreach (var item in propertyList)
            {
                var stands = item.GetValue(standArea) as string[];
                if (stands.Contains(stand))
                {
                    var result = new StandAreaEnum();
                    StandAreaEnum.TryParse(item.Name, out result);
                    return result;
                }
            }

            return null;
        }

    }

    public  class WebSocketHelper
    {
        private static Dictionary<string, Dictionary<string, WebSocketStore>> _wsPool = new Dictionary<string, Dictionary<string, WebSocketStore>>()
        {
            {WebSocketAction.ExcelProgeress.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.PushMessage.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.East1.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.East2.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.East3.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.East5.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.East6.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.EastConnect.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.West1.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.West2.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.West3.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.West5.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.West6.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.WestConnect.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.North.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.RemotePositionT1.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.EastRemotePositionT2.ToString(),new Dictionary<string, WebSocketStore>()},
            {WebSocketAction.WestRemotePositionT2.ToString(),new Dictionary<string, WebSocketStore>()},

        };
        //private static Dictionary<string, WebSocket> _connectPool = new Dictionary<string, WebSocket>();//连接Websocket的用户连接池
        public async Task ProcessHandler(AspNetWebSocketContext context)
        {
            WebSocket socket = context.WebSocket;
            string token = context.QueryString["Token"];
            string wsAct = context.QueryString["WsAct"];
            string user = context.QueryString["User"];
            var wsAction=((WebSocketAction)Enum.Parse(typeof(WebSocketAction), wsAct)).ToString();
            #region 用户添加连接池

            if (!_wsPool.ContainsKey(wsAction))
            {
                return;
            }

            var socketStore = new WebSocketStore()
            {
                User=user,
                Token = token,
                WebSocketInstance = socket
            };
            //第一次open时，添加到连接池中
            if (!_wsPool[wsAction].ContainsKey(token)&& !user.IsEmpty()&&!token.IsEmpty())
            {
                _wsPool[wsAction].Add(token, socketStore);//不存在，添加
            }
            else if (!Equals(socketStore, _wsPool[wsAction][token])) //当前对象不一致，更新
            {
                _wsPool[wsAction][token] = socketStore;
            }

            if (wsAction!= WebSocketAction.ExcelProgeress.ToString())
            {
                if (!_wsPool["PushMessage"].ContainsKey(token) && !user.IsEmpty()&&!token.IsEmpty())
                {
                    _wsPool["PushMessage"].Add(token, socketStore);//不存在，添加
                }
                else if (!Equals(socketStore, _wsPool["PushMessage"][token])) //当前对象不一致，更新
                {
                    _wsPool["PushMessage"][token] = socketStore;
                }
            }
            #endregion

            try
            {
                while (socket.State == WebSocketState.Open)
                {
                    var buffer = new ArraySegment<byte>(new byte[1024]);
                    var receivedResult = socket.ReceiveAsync(buffer, CancellationToken.None);
                    if (receivedResult.Result.MessageType == WebSocketMessageType.Close)
                    {
                        await socket.CloseAsync(WebSocketCloseStatus.Empty, string.Empty, CancellationToken.None);
                    }
                    if (socket.State == WebSocketState.Open)
                    {
                        var sendBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(receivedResult.Result.ToString()));
                        await socket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
                    }
                }
                var mongoDb = MongoDbInstanceStore.DataStoreInstance;
                var filterBuilder = Builders<BsonDocument>.Filter;
                var wsActFilter =
                    filterBuilder.Or(
                        filterBuilder.Eq("WsAct", (WebSocketAction)Enum.Parse(typeof(WebSocketAction), wsAct)),
                        filterBuilder.Eq("WsAct", WebSocketAction.ExcelProgeress));
                var filter = filterBuilder.And(filterBuilder.Eq("WsToken", token), wsActFilter);
                mongoDb.DelSingleDocument("DataStore", "WebSocketPool", filter);

                _wsPool[wsAction].Remove(token);
                _wsPool["PushMessage"].Remove(token);
                socket.Abort();
                //socket.Dispose();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                _wsPool[wsAction].Remove(token);
                _wsPool["PushMessage"].Remove(token);
                throw;
            }
            
        }
        public static async Task SendExportProgress(string socketToken, double progress)
        {
            string  wsAction = WebSocketAction.ExcelProgeress.ToString();
            if (_wsPool[wsAction].ContainsKey(socketToken))
            {
                var buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(Math.Round(progress, 2).ToString(CultureInfo.InvariantCulture)));
                await _wsPool[wsAction][socketToken].WebSocketInstance.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
            }
        }
        public static async Task PushMissionMsg(StandAreaEnum? area, StaffMissionDataModel msg)
        {
            //根据area循环发送
            var sendData = JsonConvert.SerializeObject(msg);
            var buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(sendData));
            if (area!=null)
            {
                foreach (var item in _wsPool[area.GetValueOrDefault().ToString()])
                {
                    if (item.Value.WebSocketInstance.State == WebSocketState.Open)
                    {
                        await item.Value.WebSocketInstance.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
                    }
                }
                // await _wsPool[""][""].SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
            }
            else
            {
                foreach (var item in _wsPool["PushMessage"])
                {
                    if (item.Value.WebSocketInstance.State == WebSocketState.Open)
                    {
                        await item.Value.WebSocketInstance.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
                    }
                    
                }
            }
        }
    }


    public class ttttttt
    {
        public XSSFWorkbook DataConvertToExcel<T>(IEnumerable<T> data, string sheetName = "工作表1", List<string> title = null, string userToken = null)
        {
            //JArray DataObj;1
            var enumerable = data as T[] ?? data.ToArray();
            //var dataObj = (JArray)JsonConvert.DeserializeObject(enumerable.ToJson());
            var dataObj = enumerable.ToList();
            var dataLength = dataObj.Count;
            List<string> titleKey = new List<string>();
            XSSFWorkbook nopiObj = new XSSFWorkbook();//创建Excel对象
            IFont Font = nopiObj.CreateFont();//设置字体Style
            Font.FontName = "微软雅黑";
            ICellStyle cellStyle = nopiObj.CreateCellStyle();
            cellStyle.SetFont(Font);

            ISheet sheet = nopiObj.CreateSheet(sheetName);//创建Excel工作表
            IRow row = sheet.CreateRow(0);//创建行
            int c = 0;
            //编辑首行(标题)
            if (title == null)
            {

                foreach (var DataObject in dataObj[0].ToBsonDocument().ToList())
                {

                    string titleTemp = DataObject.Name.ToString();
                    //string titleTemp = DataObject.Path.Split('.')[1];
                    row.CreateCell(c).SetCellValue(titleTemp);
                    row.GetCell(c).CellStyle = cellStyle;
                    titleKey.Add(titleTemp);
                    c++;
                }
            }
            else
            {
                try
                {
                    if (dataObj.Count > 0)
                    {
                        //foreach (var dataObject in dataObj[0].ToBsonDocument().ToList())
                        //{

                        //    string titleTemp = dataObject.Name.ToString();
                        //    titleKey.Add(titleTemp);
                        //}


                        //foreach (var dataObject in dataObj[0])
                        //{
                        //    string titleTemp = dataObject.Path.Split('.')[1];
                        //    titleKey.Add(titleTemp);
                        //}

                        //var type = dataObj[0].GetType().GetProperties();
                        var type = typeof(T).GetProperties();
                        foreach (var variable in type)
                        {
                            titleKey.Add(variable.Name);
                        }

                    }

                    foreach (var dataObject in title)
                    {

                        string titleTemp = dataObject;
                        row.CreateCell(c).SetCellValue(titleTemp);
                        row.GetCell(c).CellStyle = cellStyle;
                        c++;
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }

            }
            //编辑剩余行
            int i = 1;
            double progress = 0;
            foreach (var dataObject in dataObj)
            {
                var progressTemp = Math.Round((double)i / dataLength, 2);
                if (!(progressTemp == progress))
                {
                    progress = progressTemp;
                    //Task.Run(() => { sendProgerss(userToken, progressTemp); });
                }

                //sendProgerss.BeginInvoke(userToken, (double) i / dataLength, null, null);

                //WebSocketHelper.SendExportProgress(userToken, (double)i / dataLength);
                //sendProgerss(userToken, (double)i / dataLength);
                IRow rowtemp = sheet.CreateRow(i);
                for (int keyCount = 0; keyCount < titleKey.Count; keyCount++)
                {

                    string CellVal = "";
                    var type = dataObject.GetType().GetProperty(titleKey[keyCount]);
                    var valTemp = type?.GetValue(dataObject);
                    CellVal = valTemp?.ToString();
                    rowtemp.CreateCell(keyCount).SetCellValue(CellVal);
                    rowtemp.GetCell(keyCount).CellStyle = cellStyle;
                }
                //自动适应行宽
                sheet.AutoSizeColumn(i - 1);
                i++;
            }
            return nopiObj;
        }
    }
}